--if isClient() then
--    return
--end

ESR = ESR or {}
ESR.Rankings = ESR.Rankings or {}
ESR.Rankings.Server = ESR.Rankings.Server or {}
ESR.Rankings.Server.Commands = ESR.Rankings.Server.Commands or {}

function ESR.Rankings.Server.Commands.BroadcastAdmin(player, args)
    if string.lower(player:getAccessLevel()) == "admin" then
        ESR.Rankings.Server.BroadcastAdmin(player)
    end
end

function ESR.Rankings.Server.Commands.ScoreboardOpened(player, args)
    print("ESR.Rankings.Server.Commands.ScoreboardOpened")
    ESR.Rankings.Server.BroadcastBase(player)
end

function ESR.Rankings.Server.Commands.SavePlayerPreferences(player, args)
    local opened = args[2]
    local x = args[3]
    local y = args[4]

    local data = ESR.Rankings.Server.data
    local userName = player:getUsername()
    if data["preferences"] == nil then
        data["preferences"] = {}
    end
    local dataPlayerPreferences = data.preferences[userName] or {}

    dataPlayerPreferences["opened"] = opened
    if x then
        dataPlayerPreferences["x"] = x
    end
    if y then
        dataPlayerPreferences["y"] = y
    end

    ESR.Rankings.Server.data.preferences[userName] = dataPlayerPreferences
    ESR.Rankings.Server.Save()
end

function ESR.Rankings.Server.Commands.RetrievePlayerPreferences(player, args)
    local data = ESR.Rankings.Server.data
    local userName = player:getUsername()
    if data["preferences"] == nil then
        data["preferences"] = {}
    end

    local preferences = data.preferences[userName] or {}
    sendServerCommand(player, ESR.Rankings.Shared.MODULE_NAME, "PlayerPreferencesFromServer", preferences)
end

function ESR.Rankings.Server.Commands.ForceBroadcast(player, args)
    if string.lower(player:getAccessLevel()) == "admin" then
        ESR.Rankings.Server.BroadcastBase()
        ESR.Rankings.Server.BroadcastAdmin(player)
        ESR.Logger.info("ForceBroadcast", { "ADMIN", player:getUsername() })
    else
        ESR.Logger.error("ForceBroadcast", { "NO PERMISSION", player:getUsername() })
    end
end

-- TODO change to send info to ALL logged admins
function ESR.Rankings.Server.BroadcastAdmin(player)
    sendServerCommand(player, ESR.Rankings.Shared.MODULE_NAME, "DataToAdmin", ESR.Rankings.Server.data)
    ESR.Logger.info("BroadcastAdmin", { player:getUsername() })
end

function ESR.Rankings.filterPlayers()
    local allPlayers = ESR.Rankings.Server.data["players"] or {}
    local filteredList = {}
    for k, v in pairs(allPlayers) do
        if v["hidden"] == nil or not v["hidden"] then
            filteredList[k] = v
        end
    end
    return filteredList
end

function ESR.Rankings.stockData()
    local filteredList = {}
    local data = ESR.Rankings.Server.data
    filteredList["data"] = data
    return filteredList
end

function ESR.Rankings.Server.BroadcastBase(player)
    if player then
        sendServerCommand(player, ESR.Rankings.Shared.MODULE_NAME, "DataFromServer", ESR.Rankings.filterPlayers())
    else
        sendServerCommand(ESR.Rankings.Shared.MODULE_NAME, "DataFromServer", ESR.Rankings.filterPlayers())
        --local filterPlayers = ESR.Rankings.filterPlayers()
        --sendClientCommand(getPlayer(),ESR.Rankings.Shared.MODULE_NAME, "DataFromServer", filterPlayers)
    end
end

function ESR.Rankings.Server.BroadcastStock(player)
    local list = {}
    list["stock"] = ESR.Rankings.Server.data["stock"] or {}
    list["stockPrev"] = ESR.Rankings.Server.data["stockPrev"] or {}
    list["numStock"] =  ESR.Rankings.Server.data["numStock"]
    local num =  ESR.Rankings.Server.data["numStock"]
    args = {
        umStock = 9,
        numStock = num
    }
    local args2 = {
        data = ESR.Rankings.Server.data
    }
    if player then
        sendServerCommand(player, ESR.Rankings.Shared.MODULE_NAME, "StockDataFromServer",list )
    else
        sendServerCommand(ESR.Rankings.Shared.MODULE_NAME, "StockDataFromServer",  args)
        sendServerCommand(ESR.Rankings.Shared.MODULE_NAME, "StockDataFromServer",  args2)
        sendServerCommand(ESR.Rankings.Shared.MODULE_NAME, "StockDataFromServer",  ESR.Rankings.stockData())
    end
end

function ESR.Rankings.Server.EveryHoursUpdate()
    ESR.Rankings.Server.Save() --TODO better checking sandboxVars day duration
end

function ESR.Rankings.Server.Save()
    -- local data = ESR.Rankings.Server.data
    -- local dataStr = ESR.Rankings.Shared.MODDATA
    ModData.add(ESR.Rankings.Shared.MODDATA, ESR.Rankings.Server.data)
end
local function EveryTenMinutes()
    local serverData = ESR.Rankings.Server.data
    if serverData and serverData["initialised"] then
        if (getGameTime():getHour() == 20) then
            for i = 1, serverData["numStock"], 1 do
                serverData["stockPrev"][i] = serverData["stock"][i]
            end
        end
        --if ((getGameTime():getHour() >= 0 and getGameTime():getHour() <= 7 and getGameTime():getMinutes() == 20)
        --        or (getGameTime():getHour() >= 20 and getGameTime():getHour() <= 24)) then
        -- if (getGameTime():getMinutes() == 20) then
        if (getGameTime():getMinutes() == 20) then
            local numStock = serverData["numStock"] or 9
            for i = 1, numStock, 1 do
                local currentPrice = serverData["stock"][i]
                local changes = 0
                -- 千分之三概率暴涨暴跌
                if (ZombRand(0, 100) < 2) then
                    if (ZombRand(0, 2) == 0) then
                        changes = -ZombRand(25, 45)
                    else
                        changes = ZombRand(25, 45)
                    end
                else
                    -- 根据当前股价设置波动范围
                    -- 当前股价<10,波动范围-2, 3
                    if currentPrice < 10 then
                        changes = ZombRand(-2, 3)
                        -- 当前股价<50,波动范围-3, 3
                    elseif currentPrice < 50 then
                        changes = (ZombRand(-3, 3) * currentPrice) / 100
                        -- 当前股价<100,波动范围-5, 5
                    elseif currentPrice < 100 then
                        changes = (ZombRand(-5, 5) * currentPrice) / 100
                        -- 当前股价<200,波动范围-7, 6
                    elseif currentPrice < 200 then
                        changes = (ZombRand(-7, 6) * currentPrice) / 100
                        -- 当前股价>200,波动范围-10, 8
                    else
                        changes = (ZombRand(-10, 8) * currentPrice) / 100
                    end
                end

                local new_val = serverData["stock"][i]

                if (changes < 0) then
                    new_val = math.floor(new_val + changes)
                    if changes <= -10 then
                        serverData["news"][1] = serverData["news"][2]
                        serverData["news"][2] = serverData["news"][3]
                        serverData["news"][3] = getText("IGUI_RISKY_INVEST_BIG_CHANGE_DOWN",ESR.Rankings.Shared.StockName[i],getGameTime():getHour(),getGameTime():getMinutes())
                    end
                else
                    new_val = math.ceil(new_val + changes)
                    if changes >= 10 then
                        serverData["news"][1] = serverData["news"][2]
                        serverData["news"][2] = serverData["news"][3]
                        serverData["news"][3] = getText("IGUI_RISKY_INVEST_BIG_CHANGE_UP",ESR.Rankings.Shared.StockName[i],getGameTime():getHour(),getGameTime():getMinutes())
                    end
                end

                if (new_val < 1) then
                    new_val = 1
                end
                serverData["stock"][i] = new_val
            end
        end
    end
    ESR.Rankings.Server.data["stock"] = serverData["stock"]
    ESR.Rankings.Server.data["stockPrev"] = serverData["stockPrev"]
    ESR.Rankings.Server.data["news"] = serverData["news"]
    ESR.Rankings.Server.data["numStock"] = serverData["numStock"]
end

function ESR.Rankings.Server.EveryTenMinutesUpdate()
    EveryTenMinutes()

    local rate = SandboxVars.GSBQoL_Rankings.UpdateRate
    local rateMinutes = rate == 4 and 60 or (rate * 10)
    local minutes = getGameTime():getMinutes()

    if math.fmod(minutes, rateMinutes) == 0 then
        ESR.Rankings.Server.BroadcastBase()

    end
    ESR.Rankings.Server.BroadcastStock()
end

function ESR.Rankings.Server.OnInitGlobalModData(isNewGame)
    print("=====================ESR.Rankings.Server.OnInitGlobalModData==========================")

    if not ModData.exists(ESR.Rankings.Shared.MODDATA) then
        ModData.create(ESR.Rankings.Shared.MODDATA)
    end
    local data = ModData.get(ESR.Rankings.Shared.MODDATA)

    ESR.Rankings.Server.data = data
end

-- 充值
function ESR.Rankings.Server.Commands.Deposit(player, args)
    local userName = args[1]
    local addFund = args[2]

    local data = ESR.Rankings.Server.data
    local dataPlayer = data.players[userName]

    dataPlayer["fund"] = (dataPlayer["fund"] or 0) + addFund

    ESR.Rankings.Server.data.players[userName] = dataPlayer

    ESR.Rankings.Server.BroadcastBase()
end

-- 提现
function ESR.Rankings.Server.Commands.Withdraw(player, args)
    local userName = args[1]

    local data = ESR.Rankings.Server.data
    local dataPlayer = data.players[userName]

    dataPlayer["fund"] = 0

    ESR.Rankings.Server.data.players[userName] = dataPlayer

    ESR.Rankings.Server.BroadcastBase()
    end

-- 加买股
function ESR.Rankings.Server.Commands.AddBuys(player, args)
    local userName = args[1]
    local addBuys = args[2]
    local stockIndex = args[3]

    local data = ESR.Rankings.Server.data
    local dataPlayer = data.players[userName]

    dataPlayer["buys"] = (dataPlayer["buys"] or 0) + addBuys
    dataPlayer["fund"] = (dataPlayer["fund"] or 0) - addBuys
    dataPlayer["stock"][stockIndex] = (dataPlayer["stock"][stockIndex] or 0) + 1

    ESR.Rankings.Server.data.players[userName] = dataPlayer

    ESR.Rankings.Server.BroadcastBase()
end

-- 加卖股
function ESR.Rankings.Server.Commands.AddSells(player, args)
    local userName = args[1]
    local addSells = args[2]
    local stockIndex = args[3]

    local data = ESR.Rankings.Server.data
    local dataPlayer = data.players[userName]

    dataPlayer["sells"] = (dataPlayer["sells"] or 0) + addSells
    dataPlayer["fund"] = (dataPlayer["fund"] or 0) + addSells
    dataPlayer["stock"][stockIndex] = dataPlayer["stock"][stockIndex] - 1

    ESR.Rankings.Server.data.players[userName] = dataPlayer

    ESR.Rankings.Server.BroadcastBase()
end

-- 创建玩家基础数据
function ESR.Rankings.Server.Commands.CreatePlayer(player,args)
    print("===============ESR.Rankings.Server.Commands.CreatePlayer====================")
    if (args ~= nil and args[1] ~= nil) then
        local serverData = ESR.Rankings.Server.data
        if (serverData.players == nil) then
            serverData.players = {}
        end
        local serverDataPlayer = serverData.players[args[1]]
        if(serverDataPlayer == nil) then
            serverDataPlayer = {}
            serverDataPlayer["stock"] = serverDataPlayer["stock"] or {}
            serverDataPlayer["buys"] = 0
            serverDataPlayer["sells"] = 0
            if SandboxVars.Op_StockRandomMoney then
                if SandboxVars.Op_StockMoney ~= nil then
                    serverDataPlayer["fund"] = ZombRand(1, SandboxVars.Op_StockMoney)
                else
                    serverDataPlayer["fund"] = ZombRand(1, 1000)
                end
            else
                if SandboxVars.Op_StockMoney ~= nil then
                    serverDataPlayer["fund"] = SandboxVars.Op_StockMoney
                end
            end
        end
    end
    ESR.Rankings.Server.BroadcastBase()
    ESR.Rankings.Server.BroadcastStock(player)
end

function ESR.Rankings.Server.OnClientCommand(module, command, player, args)

    if module == ESR.Rankings.Shared.MODULE_NAME then
        print("OnClientCommand=========", command)

        local userName = ""
        if args and args[1] then
            userName = args[1]
        end
        if string.lower(player:getAccessLevel()) == "admin" or userName == player:getUsername() then
            ESR.Rankings.Server.Commands[command](player, args)
        else
           --  ESR.Logger.error(command, { "userName not match", player:getUsername(), "username: " .. userName })
            ESR.Logger.error("UserMismatch", { Command = command, Player = player:getUsername(), Username = userName })
        end
    end
end


Events.OnInitGlobalModData.Add(ESR.Rankings.Server.OnInitGlobalModData)
Events.OnClientCommand.Add(ESR.Rankings.Server.OnClientCommand)
Events.EveryTenMinutes.Add(ESR.Rankings.Server.EveryTenMinutesUpdate)
Events.EveryHours.Add(ESR.Rankings.Server.EveryHoursUpdate)


--------------------------------------------------



-- Events.EveryTenMinutes.Add(EveryTenMinutes)

local function OnGameStart()
    print("============================Server.OnGameStart=============================")
    local modData = ESR.Rankings.Server.data

    modData["stock"] = modData["stock"] or {}
    modData["stockPrev"] = modData["stockPrev"] or {}
    modData["initialised"] = false
    modData["numStock"] = 9

    for i = 1, modData["numStock"], 1 do
        if (modData["stock"][i] == nil or modData["stockPrev"][i] == nil) then
            local maxRandStockPrice = SandboxVars.Op_StockInitMoney or 20
            modData["stock"][i] = ZombRand(1, maxRandStockPrice)
            modData["stockPrev"][i] = modData["stock"][i]
        end
    end

    -- 初始化资讯信息
    if (modData["news"] == nil) then
        modData["news"] = {}
        modData["news"][1] = SandboxVars.Op_StockNews1 or getText('IGUI_RISKY_INVEST_SCROLL_NEWS1')
        modData["news"][2] = SandboxVars.Op_StockNews2 or getText('IGUI_RISKY_INVEST_SCROLL_NEWS2')
        modData["news"][3] = SandboxVars.Op_StockNews3 or getText('IGUI_RISKY_INVEST_SCROLL_NEWS3')
    end

    modData["initialised"] = true
    ESR.Rankings.Server.data = modData
end

Events.OnGameStart.Add(OnGameStart)


